package edu.tjut.tjutcommunity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.tjut.tjutcommunity.entity.*;
import edu.tjut.tjutcommunity.mapper.PostMapper;
import edu.tjut.tjutcommunity.mapper.RecommendationsMapper;
import edu.tjut.tjutcommunity.recommend.Main.JobSetter;
import edu.tjut.tjutcommunity.service.PostService;
import edu.tjut.tjutcommunity.service.PostlogsService;
import edu.tjut.tjutcommunity.service.UserService;
import edu.tjut.tjutcommunity.utils.MessageQueueUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yhh
 * @since 2022-04-16
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
    final
    PostMapper postMapper;
    final
    MessageQueueUtils messageQueueUtils;
    final
    UserService userService;
    final
    RecommendationsMapper recommendationsMapper;
    final
    JobSetter recSetter;
    final
    PostlogsService postlogsService;

    private static final ConcurrentHashMap<Integer, Object> lock = new ConcurrentHashMap<>();


    public PostServiceImpl(PostMapper postMapper, MessageQueueUtils messageQueueUtils, UserService userService, RecommendationsMapper recommendationsMapper, JobSetter recSetter, PostlogsService postlogsService) {
        this.postMapper = postMapper;
        this.messageQueueUtils = messageQueueUtils;
        this.userService = userService;
        this.recommendationsMapper = recommendationsMapper;
        this.recSetter = recSetter;
        this.postlogsService = postlogsService;

    }

    //    @Override
//    public boolean addPost(Post post, User user, Integer ordinal) throws ClassNotFoundException, InvocationTargetException, PicNotFoundException, IllegalAccessException, NoSuchMethodException {
//        post.setUid(user.getUid());
//        post.setUsername(user.getUsername());
//        post.setAcademyName(user.getAcademyName());
//        if (ordinal != null && ordinal > 0) {
//            SetPic(post, user.getStudentId(), "_post_pic_", ordinal);
//        }
//        return postMapper.insert(post) == 1;
//    }
    //单图片上传
    @Override
    public Boolean addPost(Post post, User user) {
        post.setUid(user.getUid());
        post.setUsername(user.getUsername());
        post.setAcademyName(user.getAcademyName());
        return postMapper.insert(post) == 1;
    }

    /**
     * 根据时间和页大小和关键字获取帖子
     *
     * @param keyword
     * @param pageSize
     * @param time
     * @param type     帖子类别
     * @return
     */
    @Override
    public PageResult<Post> getPostByTimeAndPageSizeAndKey(String keyword, Integer pageSize, Date time, Integer type) {
        if (pageSize == null || pageSize <= 0) pageSize = 10;
        else pageSize = Math.min(pageSize, 10);
        if (type == null) type = 0;
        Page<Post> page = new Page<>(0, pageSize);
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("update_time", time);
        queryWrapper.eq("type", type);
        if (keyword != null && !"".equals(keyword)) {
            queryWrapper.like("title", keyword)
                    .or()
                    .like("description", keyword);
        }
        queryWrapper.orderByDesc("update_time");
        //在这里执行推荐逻辑，获取或者不获取推荐，并返回。
        Page<Post> postPage = postMapper.selectPage(page, queryWrapper);
        return new PageResult<>(postPage.getRecords(), postPage.getPages());
    }

    @Override
    public PageResult<Post> getPostByPageAndKey(String keyword, Integer pageSize, Integer pageNo, Integer type) {
        if (pageSize == null || pageSize <= 0) pageSize = 10;
        else pageSize = Math.min(pageSize, 10);
        if (type == null) type = 0;
        Page<Post> page = new Page<>(pageNo, pageSize);
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", type);
        if (keyword != null && !"".equals(keyword)) {
            queryWrapper.like("title", keyword)
                    .or()
                    .like("description", keyword);
        }
        queryWrapper.orderByDesc("update_time");
        Page<Post> postPage = postMapper.selectPage(page, queryWrapper);
        return new PageResult<>(postPage.getRecords(), postPage.getPages());
    }


    /**
     * 点赞并通知
     *
     * @param pid
     * @param user
     * @return
     */
    @Override
    public Boolean likeInc(Integer pid, User user) {
        if (postMapper.likeInc(pid) == 1) {
            //通知
            //如果是自己点赞，不通知
            Post p = getUidAndUsernameAndFloorsByPid(pid);
            if (!Objects.equals(p.getUid(), user.getUid())) {
                User u = userService.getStuIdById(p.getUid());
                NoticeMessage likeMessage = NoticeMessage.getLikeMessage(user, pid);
                messageQueueUtils.sendMessage(u.getStudentId(), likeMessage);
            }
            return true;
        }
        return false;
    }

    /**
     * 更新帖子时间
     *
     * @param pid
     * @return
     */
    @Override
    public Boolean updateTime(Integer pid) {
        Post post = new Post();
        post.setPid(pid);
        post.setUpdateTime(new Date());
        return postMapper.updateById(post) == 1;
    }


    /**
     * 根据pid获得uid和username
     *
     * @param pid
     * @return
     */
    @Override
    public Post getUidAndUsernameAndFloorsByPid(Integer pid) {
        QueryWrapper<Post> qw = new QueryWrapper<>();
        qw.select("username", "uid", "floors");
        qw.eq("pid", pid);
        return postMapper.selectOne(qw);
    }

    @Override
    public Boolean delPost(Integer pid, User user) {
        Integer uid = user.getUid();
        Post post = getUidAndUsernameAndFloorsByPid(pid);
        if (post == null || !post.getUid().equals(uid)) return false;
        return postMapper.deleteById(pid) == 1;
    }

    @Override
    public Boolean floorsInc(Integer pid) {
        Post post = postMapper.selectById(pid);
        try {
            //自旋
            while (lock.get(pid) != null) ;
            lock.put(pid, post);
            //comment里fid为此楼的总数+1
            post.setFloors(post.getFloors() + 1);
            postMapper.updateById(post);
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            lock.remove(pid);
        }
    }

    @Override
    public PageResult<Post> getMyPost(Integer uid, Integer pageNo, String keyword) {
        int pageSize = 10;
        Page<Post> page = new Page<>(pageNo, pageSize);
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid", uid);
        if (keyword != null && !"".equals(keyword)) {
            queryWrapper.like("title", keyword)
                    .or()
                    .like("description", keyword);
        }

        queryWrapper.orderByDesc("create_time");
        Page<Post> postPage = postMapper.selectPage(page, queryWrapper);
        return new PageResult<>(postPage.getRecords(), postPage.getPages());
    }

    @Override
    public Post getPostById(String pid) {
        return postMapper.selectById(pid);
    }

    @Override
    public List<Post> getPostByIds(Set<Integer> pids) {
        if (pids.isEmpty()) return Collections.EMPTY_LIST;
        return postMapper.selectBatchIds(pids);
    }

    @Override
    public List<Post> getRecPost(String inRecDate) {
        QueryWrapper<Post> qw = new QueryWrapper<>();
        qw.gt("update_time", inRecDate);
        return postMapper.selectList(qw);
    }

    @Override
    public PageResult<Post> getRecommendPost(User user, Integer derive, Integer pageNo, Integer size) {

//        int pageSize = 10;
//        Page<Post> page = new Page<>(pageNo, pageSize);
//        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("uid", uid);
//        if (keyword != null && !"".equals(keyword)) {
//            queryWrapper.like("title", keyword)
//                    .or()
//                    .like("description", keyword);
//        }
//
//        queryWrapper.orderByDesc("create_time");
//        Page<Post> postPage = postMapper.selectPage(page, queryWrapper);
//        return new PageResult<>(postPage.getRecords(), postPage.getPages());
        //随机获取吧，获取还未被推荐的帖子
        Page<Recommendations> page = new Page<>(pageNo, size);
        QueryWrapper<Recommendations> qw = new QueryWrapper<>();
        qw.eq("uid", user.getUid());
        if (derive != null)
            qw.eq("derive_algorithm", derive);
        qw.eq("has_recommend", 0);
        qw.orderByDesc("create_time");
        Page<Recommendations> recommendationsPage = recommendationsMapper.selectPage(page, qw);


        List<Recommendations> recommendations = recommendationsPage.getRecords();
        //生成推荐的操作应该再开一个子线程去处理,然后直接返回
        if (recommendations.size() < size) {
            //尝试异步重新生成推荐
            recSetter.executeInstantJobForSingleUserAsync(user, derive);
        }


        //置为已推荐
        setHasRecommend(recommendations.stream().map(Recommendations::getPid).collect(Collectors.toList()));
        //给post加上标识
        List<Post> posts = getPostByIds(recommendations.stream().map(Recommendations::getPid).collect(Collectors.toSet()));
        if (posts != null) {
            posts.stream().forEach(post -> recommendations.stream().forEach(recommendation -> {
                if (post.getPid().equals(recommendation.getPid()))
                    post.setRecommendType(recommendation.getDeriveAlgorithm());
            }));
        }
        return new PageResult<>(posts, recommendationsPage.getPages());
    }


    private void setHasRecommend(List<Integer> collect) {
        if (collect.isEmpty()) return;
        UpdateWrapper<Recommendations> ud = new UpdateWrapper<>();
        ud.in("pid", collect).set("has_recommend", 1);
        recommendationsMapper.update(null, ud);
    }

    private Set<Integer> getUserRecommendPid(User user) {
        if (user == null) return Collections.EMPTY_SET;
        QueryWrapper<Recommendations> qw = new QueryWrapper<>();
        qw.eq("uid", user.getUid());
        return recommendationsMapper.selectList(qw).stream().map(Recommendations::getPid).collect(Collectors.toSet());
    }

    @Override
    public boolean isMyPost(Integer pid, User user) {
        QueryWrapper<Post> qw = new QueryWrapper<>();
        qw.eq("pid", pid);
        Post post = postMapper.selectOne(qw);
        return post != null && post.getUid().equals(user.getUid());
    }

    @Override
    public List<Integer> getMyPosts(Integer uid) {
        QueryWrapper<Post> qw = new QueryWrapper<>();
        qw.eq("uid", uid);
        return postMapper.selectList(qw).stream().map(Post::getPid).collect(Collectors.toList());
    }
}
